package com.yuan.view;

import com.yuan.ayuancity.entity.Admins;
import com.yuan.ayuancity.entity.Users;
import com.yuan.security.SecurityUser;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpRequest;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Date;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;

/**
 * <p>
 *      Jwt Token工具类
 *      目前打算生成jwt ==>存放账户名，用户实体类（Admins或者Users)
 *      后期打算：存放账户名和一个uuid,把用户实体类存放到redis中，到时候根据uuid获取实体类
 * </p>
 *
 * @author asuyuan
 * @since 2023/3/4
 *
 */
@Component
@Data
public class JwtHelper {
    // @Value("${name}")
    // private static Sring  name ; // 无法注入
    // 解决：
    // 加一个@Value加在set方法中
    // @Value("${name}")
    // public void setName(String name){
    //     类名.name = name;
    // }
    // 定义 token 返回头部
    public  String header="Authorization";
    //token 前缀
    public  String tokenPrefix="YuanCity";
    //签名密钥
    public  String secret="ASuYuanYuan123";
    // 有效期,单位1毫秒，设置为30分钟
    public  long expireTime=1*1000*60*30;
    //存进客户端的 token 的 key 名
    public  final String USER_LOGIN_TOKEN = "token";


    /**
     * 从数据数据声明中创建TOKEN
     * JWT 构成: header, payload, signature
     * @param claims 数据声明
     * @return token 值
     */
    public  String createClaimToken(Map<String,Object> claims){
        //过期时间
        Date expirationDate = new Date(System.currentTimeMillis() + expireTime);
        String token = Jwts.builder().setClaims(claims)
                .signWith(SignatureAlgorithm.HS512, secret)
                .setExpiration(expirationDate)
                .compact();
        return token;
    }
    /*
    * 从token中获取数据声明
    */
    public Claims  getClaimsByToken(String token){
        Claims claims=null;
        claims =  Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
        return claims;
    }
     /*
        根据用户创建token
      */
    public <T>String createUserToken(SecurityUser userDetails, T t){
        Map<String, Object> claims = new HashMap<>();
        Class  aClass = t.getClass();
        if(Admins.class.equals(aClass)){
            claims.put("admin", userDetails.getAdmins());
        }else{
            claims.put("user", userDetails.getUsers());
        }
        claims.put(Claims.SUBJECT, userDetails.getUsername());
        claims.put(Claims.ISSUED_AT, new Date());
        return createClaimToken(claims);
    }


     /*
       从token中获取用户名
      */
    public String getNameByToken(String token){
        String name=null;
        name = getClaimsByToken(token).getSubject();
        return name;
    }
    /*
        验证token是否过期
     */
    public Boolean isTokenExpired(String token){
        Claims claims = getClaimsByToken(token);
        Date expiration = claims.getExpiration();
        if (expiration.getTime()-new Date().getTime()<=1000*60*5){
            System.out.println("快到期了，有效期小于5分钟");
            //这里可以调用更新token 返回新token
        }
        return expiration.before(new Date());
    }
     /*
        token到期,更新token
      */
    public String refreshTokenExpired(String token){
        Claims oldToken = getClaimsByToken(token);
        oldToken.put(Claims.ISSUED_AT, new Date(System.currentTimeMillis() + expireTime));
        String newToken = createClaimToken(oldToken);
        return newToken;
    }
    /*
        获取请求头token
     */
   public String getTokenByHttp(HttpServletRequest request){
       String token = request.getHeader(header);
       //验证token不为空，并且前缀正确
       if (StringUtils.isNotEmpty(token)&&token.startsWith(tokenPrefix)){
           //去掉前缀
           token = token.replace(tokenPrefix, "");
       }
       return token;
   }

   /*
      验证token与当前用户是否一致
    */
    public <T>Boolean validateToken(String token, UserDetails userDetails,T t){
        String name=null;
        T user=(T)userDetails;
        Class  aClass = t.getClass();
        if(Admins.class.equals(aClass)){
            name=((Admins) t).getAdminAccount();
        }else{
            name=((Users) t).getUserAccount();
        }
        //token的名字
        String nameByToken = getNameByToken(token);
        return (name.equals(nameByToken))&&(!isTokenExpired(token));
    }

    public static void main(String[] args) {
        Map map=new HashMap();
        map.put("username", "suyuan");
        map.put("sex", "男");
        JwtHelper jwtHelper=new JwtHelper();
        String token = jwtHelper.createClaimToken(map);
        System.out.println("token:"+token);
        System.out.println("解析token:"+jwtHelper.getClaimsByToken(token).toString());
        System.out.println("SUBJECT用户名:"+jwtHelper.getNameByToken(token));
        System.out.println("username:"+jwtHelper.getClaimsByToken(token).get("username"));
        System.out.println("是否过期:"+jwtHelper.isTokenExpired(token));
        System.out.println("过期时间:"+jwtHelper.getClaimsByToken(token).getExpiration());

    }


}
